package com.gitee.wsl.func.procedure.sample

import com.gitee.wsl.base.Option
import com.gitee.wsl.base.empty
import com.gitee.wsl.base.of
import com.gitee.wsl.func.procedure.Procedure
import com.gitee.wsl.func.Function

/**
 * Implementation of [Procedure] that holds on to the minimum element seen so far,
 * determined by the [Function].
 */
open class MinByProcedure<T, V : Comparable< V>>(
    protected val function: Function<in T, out V>
) : Procedure<T> {
    var isVisitedAtLeastOnce: Boolean = false
        protected set
    private var result: T? = null
    protected var cachedResultValue: V? = null

    fun getResult(): T? {
        if (!this.isVisitedAtLeastOnce) {
            throw NoSuchElementException()
        }
        return this.result
    }

    val resultOptional: Option<T?>
        get() {
            if (!this.isVisitedAtLeastOnce) {
                return Option.empty()
            }
            return Option.of(this.result)
        }

    override fun value(each: T) {
        if (this.isVisitedAtLeastOnce) {
            val eachValue = this.function(each)
            if (eachValue.compareTo(this.cachedResultValue!!) < 0) {
                this.result = each
                this.cachedResultValue = eachValue
            }
        } else {
            this.isVisitedAtLeastOnce = true
            this.result = each
            this.cachedResultValue = this.function(each)
        }
    }

}
